Skip to content

Admin backend - #40

Merged
JinethBosilu merged 4 commits into
mainfrom
admin-backend
Mar 13, 2026
Merged

Admin backend#40
JinethBosilu merged 4 commits into
mainfrom
admin-backend

Conversation

@LPK98

@LPK98 LPK98 commented Mar 13, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings March 13, 2026 04:49

@JinethBosilu JinethBosilu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@JinethBosilu
JinethBosilu merged commit 6e83919 into main Mar 13, 2026
6 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds admin-focused backend capabilities to the CrimeLink Analyzer service, introducing database backup/restore functionality and persisted system settings management exposed via /api/admin/**.

Changes:

  • Added BackupService + BackupMetadata persistence and new admin endpoints to create/restore/list backups.
  • Added SystemSettingsService + SystemSetting persistence and admin endpoints to get/update system settings with validation.
  • Added backup directory configuration and ignored local backups output in .gitignore.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/main/resources/application.properties Adds configurable backup.directory property.
src/main/java/com/crimeLink/analyzer/service/SystemSettingsService.java Implements defaulted settings retrieval and validated updates persisted to DB.
src/main/java/com/crimeLink/analyzer/service/BackupService.java Implements JDBC-based backup creation and SQL-script restore from filesystem.
src/main/java/com/crimeLink/analyzer/repository/SystemSettingRepository.java JPA repository for SystemSetting.
src/main/java/com/crimeLink/analyzer/repository/BackupMetadataRepository.java JPA repository for BackupMetadata and ordered listing.
src/main/java/com/crimeLink/analyzer/entity/SystemSetting.java Adds system_settings entity with updatedAt lifecycle hook.
src/main/java/com/crimeLink/analyzer/entity/BackupMetadata.java Adds backup_metadata entity for tracking backup runs.
src/main/java/com/crimeLink/analyzer/controller/AdminController.java Adds admin-only endpoints for backup/restore/backups list and settings get/update.
src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java Restricts backup/restore/settings routes to Admin role before general /api/admin/** rule.
.gitignore Ignores backups directory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +113 to +117
String sql = Files.readString(backupFile);

// Split by semicolons and execute each statement
String[] statements = sql.split(";");
int executed = 0;
Comment on lines +64 to +66
try (BufferedWriter writer = new BufferedWriter(new FileWriter(backupFile.toFile()))) {
writer.write("-- CrimeLink Analyzer Database Backup\n");
writer.write("-- Created: " + LocalDateTime.now() + "\n");
Comment on lines +125 to +137
try {
jdbcTemplate.execute(trimmed);
executed++;
} catch (Exception stmtEx) {
// Log and continue — some statements may fail on duplicates etc.
log.warn("Skipping failed statement: {}... Error: {}",
sanitizeForLog(trimmed.substring(0, Math.min(80, trimmed.length()))),
sanitizeForLog(stmtEx.getMessage()));
}
}

log.info("Database restored from {} by {} ({} statements executed)",
sanitizeForLog(filename), sanitizeForLog(userEmail), executed);
Comment on lines +65 to +72
// Validate numeric value
int numericValue;
try {
numericValue = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"Setting '" + key + "' must be a valid integer, got: " + value);
}
Comment on lines +54 to +90
public Map<String, String> updateSettings(Map<String, String> incoming) {
for (Map.Entry<String, String> entry : incoming.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();

// Ignore unknown keys
if (!DEFAULTS.containsKey(key)) {
log.warn("Ignoring unknown setting key: {}", sanitizeForLog(key));
continue;
}

// Validate numeric value
int numericValue;
try {
numericValue = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"Setting '" + key + "' must be a valid integer, got: " + value);
}

int[] range = VALIDATION_RULES.get(key);
if (range != null && (numericValue < range[0] || numericValue > range[1])) {
throw new IllegalArgumentException(
"Setting '" + key + "' must be between " + range[0] + " and " + range[1] +
", got: " + numericValue);
}

// Upsert
SystemSetting setting = settingRepo.findBySettingKey(key)
.orElseGet(() -> {
SystemSetting s = new SystemSetting();
s.setSettingKey(key);
return s;
});
setting.setSettingValue(value);
settingRepo.save(setting);
}
Comment on lines +112 to +131
try {
String sql = Files.readString(backupFile);

// Split by semicolons and execute each statement
String[] statements = sql.split(";");
int executed = 0;

for (String stmt : statements) {
String trimmed = stmt.trim();
// Skip empty lines and comments
if (trimmed.isEmpty() || trimmed.startsWith("--")) {
continue;
}
try {
jdbcTemplate.execute(trimmed);
executed++;
} catch (Exception stmtEx) {
// Log and continue — some statements may fail on duplicates etc.
log.warn("Skipping failed statement: {}... Error: {}",
sanitizeForLog(trimmed.substring(0, Math.min(80, trimmed.length()))),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants